package com.zzy.jwt.jwtfilter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zzy.jwt.pojo.Response;
import com.zzy.jwt.pojo.User;
import com.zzy.jwt.utils.JWTUtil;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author Lucas-zhang
 * @description TODO
 * @date 2022-03-22 14:07
 */
public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    /**
     * 通过构造器注入拦截的Url，请求方法没有限制
     * @param antPathRequestUrl url
     */
    public JWTAuthenticationFilter(String antPathRequestUrl) {
        super(new AntPathRequestMatcher(antPathRequestUrl, "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        // 从JSON中读取请求参数
        User user = new ObjectMapper().readValue(request.getInputStream(), User.class);

        // 获取用户名和密码
        String username = user.getUsername();
        String password = user.getPassword();

        // 构造Token，使用UsernamepasswordAuthenticationToken
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        // 设置一些客户端IP等信息
        setDetails(request, token);
        // 交给AuthenticationManager进行认证
        return this.getAuthenticationManager().authenticate(token);
    }

    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        ObjectMapper objectMapper = new ObjectMapper();
        Response myResponse = new Response();
        // 设置header
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        User user = (User) authResult.getPrincipal();
        // 生成Token返回
        String token = JWTUtil.generate(user);
        myResponse.setStatusCode(HttpStatus.OK.value());
        myResponse.setMsg("登录成功!");
        myResponse.setData("Bearer " + token);

        response.setStatus(HttpStatus.OK.value());
        response.getWriter().write(objectMapper.writeValueAsString(myResponse));
    }


    /**
     * 重写认证失败后的处理方法
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        ObjectMapper objectMapper = new ObjectMapper();
        Response myResponse = new Response();
        myResponse.setStatusCode(HttpStatus.UNAUTHORIZED.value());
        if (failed instanceof LockedException) {
            myResponse.setMsg("账号被锁定!");
        } else if (failed instanceof CredentialsExpiredException) {
            myResponse.setMsg("用户密码过期!");
        } else if (failed instanceof AccountExpiredException) {
            myResponse.setMsg("用户账号过期!");
        } else if (failed instanceof DisabledException) {
            myResponse.setMsg("用户账号被禁用!");
        } else if (failed instanceof BadCredentialsException) {
            myResponse.setMsg("用户账号或密码错误!");
        }

        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.getWriter().write(objectMapper.writeValueAsString(myResponse));
    }
}
